using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using AutoTest.Core.Infrastructure.Messaging;
using log4net;

namespace AutoTest.Core.Domain.TestRunning
{
    public class TestRunner : IConsumerOf<RunTestsMessage>
    {
        private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        private readonly IAutoTestConfiguration _configuration;
        private readonly IMessageBus _messageBus;
        private readonly INUnitParser _nUnitParser;
        private StringBuilder _output;

        public TestRunner(IAutoTestConfiguration configuration, IMessageBus messageBus, INUnitParser nUnitParser)
        {
            _configuration = configuration;
            _nUnitParser = nUnitParser;
            _messageBus = messageBus;
        }

        public void Consume(RunTestsMessage msg)
        {
            if (msg.Tests.Count == 0)
                return;

            var testsForCommandLine = (msg.Tests.Count == 1 ? msg.Tests.First().Name : "");

            var exe = _configuration.TestRunnerExe;
            var args = _configuration.TestRunnerArgs + " " + testsForCommandLine;
            var process = new Process
                              {
                                  StartInfo =
                                      {
                                          FileName = exe,
                                          Arguments = args,
                                          WorkingDirectory = Path.GetDirectoryName(exe),
                                          RedirectStandardOutput = true,
                                          RedirectStandardError = true,
                                          WindowStyle = ProcessWindowStyle.Hidden,
                                          UseShellExecute = false,
                                          CreateNoWindow = true
                                      }
                              };
            process.OutputDataReceived += ProcessOnOutputDataReceived;
            process.ErrorDataReceived += ProcessOnErrorDataReceived;

            Logger.InfoFormat("Running {0} {1}", exe, args);
            _messageBus.Publish(this, new TestRunStartedMessage());
            _output = new StringBuilder();

            process.Start();

            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            process.WaitForExit();

            _messageBus.Publish(this, _nUnitParser.Parse(_output.ToString()));
        }

        private void ProcessOnOutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                Logger.Info(e.Data);
                _output.AppendLine(e.Data);
            }
        }

        private  void ProcessOnErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                Logger.Error(e.Data);
                _output.AppendLine(e.Data);
            }
        }
    }
}